package com.douding.file.controller.admin;

import com.alibaba.fastjson.JSON;
import com.douding.server.domain.Test;
import com.douding.server.dto.FileDto;
import com.douding.server.dto.ResponseDto;
import com.douding.server.enums.FileUseEnum;
import com.douding.server.exception.BusinessException;
import com.douding.server.exception.BusinessExceptionCode;
import com.douding.server.service.FileService;
import com.douding.server.service.TestService;
import com.douding.server.util.Base64ToMultipartFile;
import com.douding.server.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.List;

/*
    返回json 应用@RestController
    返回页面  用用@Controller
 */
@RequestMapping("/admin/file")
@RestController
public class UploadController {

    private static final Logger LOG = LoggerFactory.getLogger(UploadController.class);
    public static final String BUSINESS_NAME = "文件上传";
    @Resource
    private TestService testService;

    @Value("${file.path}")
    private String FILE_PATH;

    @Value("${file.domain}")
    private String FILE_DOMAIN;

    @Resource
    private FileService fileService;

    @RequestMapping("/upload")
    public ResponseDto upload(@RequestBody FileDto fileDto) throws Exception {
        LOG.info("文件上传开始，请求参数为:文件名={}，分片总数={}，该文件属于分片：{}", fileDto.getName(), fileDto.getShardTotal(), fileDto.getShardIndex());
        // 将参数的base64格式转换为
        MultipartFile multipartFile = Base64ToMultipartFile.base64ToMultipart(fileDto.getShard());

        //获取本地文件夹地址,拼接传入的参数use，得到一个本地文件夹路径，并判断是否存在，若不存在则直接创建
        String localDirPath = FILE_PATH + FileUseEnum.getByCode(fileDto.getUse());
        LOG.info("本地文件夹路径:{}", localDirPath);
        // 创建文件夹
        File dirFile = new File(localDirPath);

        // 如果目标文件夹不存在，则直接创建一个
        if (!dirFile.exists() && !dirFile.mkdirs()) {
            LOG.error("文件夹创建失败，待创建路径:{}", localDirPath);
            throw new Exception("文件夹创建失败，创建路径:" + localDirPath);
        }

        // 文件名
        String filePath = localDirPath + File.separator + fileDto.getKey() + "." + fileDto.getSuffix();
        LOG.info("文件存储地址:{}", filePath);

        // 分片文件
        String fileShardPath = filePath + "." + fileDto.getShardIndex();
        // 将文件传输到目标文件
        multipartFile.transferTo(new File(fileShardPath));
        // 判断文件是否传输完毕
        if (fileDto.getShardTotal().equals(fileDto.getShardIndex())) {
            // 传输完毕，进入合并阶段
            fileDto.setPath(filePath);
            merge(fileDto);

        }


        //更新文件表信息，无上传过这个文件则插入一条，反之直接更新索引值
        String relaPath = FileUseEnum.getByCode(fileDto.getUse()) + "/" + fileDto.getKey() + "." + fileDto.getSuffix();
        fileDto.setPath(relaPath);
        LOG.info("索引为：{}", relaPath);
        // 将文件索引存入数据库
        fileService.save(fileDto);

        ResponseDto responseDto = new ResponseDto();
        FileDto result = new FileDto();

        result.setPath(FILE_DOMAIN + relaPath);
        LOG.info("返回给前端的文件地址：{}", result.getPath());
        responseDto.setContent(result);

        return responseDto;

    }

    //合并分片
    public void merge(FileDto fileDto) throws Exception {
        LOG.info("合并分片开始");
        // 获取文件地址
        String path = fileDto.getPath();

        try (OutputStream outputStream = new FileOutputStream(path, true)) {
            for (int i = 1; i <= fileDto.getShardTotal(); i++) {
                String fileSharePaths = path + "." + i;
                FileInputStream inputStream = new FileInputStream(fileSharePaths);
                try  {
                    byte[] bytes = new byte[5 * 1024 * 1024];
                    int len;
                    while ((len = inputStream.read(bytes)) != -1) {
                        outputStream.write(bytes, 0, len);
                    }
                    inputStream.close();
                }finally {

                }
            }
        } catch (Exception e) {
            LOG.error("文件合并失败，失败原因:{}", e.getMessage(), e);
        }
        LOG.info("合并完毕");
        LOG.info("开始删除临时分片文件~~~~");
        deleteShareFile(fileDto, path);
    }

    // 删除分片临时文件
    private void deleteShareFile(FileDto fileDto, String path) {
        for (int i = 1; i < fileDto.getShardTotal() + 1; i++) {
            File file = new File(path + "." + i);
            System.gc();
            if (file.delete()) {
                LOG.info("删除文件：" + path + "." + i);
            } else {
                LOG.error("文件{}删除失败", (path + "." + i));
            }
        }
    }

    @GetMapping("/check/{key}")
    public ResponseDto check(@PathVariable String key) throws Exception {
        LOG.info("检查上传分片开始：{}", key);
        if (StringUtils.isEmpty(key)) {
            LOG.error("错误，分片key——（{}）不存在", key);
            throw new BusinessException(BusinessExceptionCode.FILEKEY_EXCEPTION);
        }
        ResponseDto responseDto = new ResponseDto();
        FileDto fileDto = fileService.findByKey(key);
        responseDto.setContent(fileDto);
        return responseDto;
    }

}//end class
